package com.bruce.tool.search.solr.search;

import com.bruce.tool.common.util.LogUtils;
import com.bruce.tool.search.solr.common.SearchUtils;
import com.bruce.tool.search.solr.domain.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;

import java.util.List;

/**
 * 功能 :
 * 查询样例
 *
 * @author : Bruce(刘正航) 上午11:03 2018/5/8
 */
@Slf4j
public abstract class AbstractSolrSearch<S,R> implements SolrSearch {

    private PageQuery pageQuery = PageQuery.build().set(1,50);

    /**
     * mm搜索参数配置
     **/
    private static final String[] mmValues = new String[]{"80%", "65%", "50%"};

    protected abstract SolrClient getSolrClient();

    /**
     * 转换结果集
     **/
    protected abstract List<S> getSuggestBeans(QueryResponse response);

    /**
     * 转换结果集
     **/
    protected abstract List<R> getSearchBeans(QueryResponse response);

    /**搜索建议**/
    public final SuggestResponse<S> suggest(KeyWords keyWords) {
        return this.suggest(pageQuery,keyWords,FilterQuerys.build());
    }

    /**搜索建议**/
    public final SuggestResponse<S> suggest(KeyWords keyWords, FilterQuerys querys) {
        return this.suggest(pageQuery,keyWords,querys);
    }

    /**搜索建议**/
    @Override
    public final SuggestResponse<S> suggest(PageQuery pageQuery, KeyWords keyWords, FilterQuerys querys) {
        long start = System.currentTimeMillis();
        SolrQuery solrQuery = new SolrQuery();

        solrQuery.setQuery(keyWords.toString());

        SearchUtils.setPageQuery(solrQuery,pageQuery);

        SearchUtils.setFilterQuery(solrQuery, querys);

        setQueryDefault(solrQuery,keyWords);

        SuggestResponse<S> suggestResponse = new SuggestResponse<>();
        QueryResponse response = executeLoopQuery(solrQuery);
        if (null == response) {return suggestResponse;}
        suggestResponse.setTotal(response.getResults().getNumFound());
        suggestResponse.setResponse(getSuggestBeans(response));
        LogUtils.info(log,"搜索耗时:{}ms",System.currentTimeMillis()-start);
        return suggestResponse;
    }

    /**搜索结果集**/
    @Override
    public final SearchResponse<R> search(PageQuery pageQuery, KeyWords keyWords, FilterQuerys filterQuerys) {
        return this.search(pageQuery,keyWords,filterQuerys,FacetQuerys.build());
    }

    /**搜索结果集**/
    @Override
    public final SearchResponse<R> search(PageQuery pageQuery, KeyWords keyWords, FilterQuerys filterQuerys,FacetQuerys facetQuerys) {
        long start = System.currentTimeMillis();
        SolrQuery solrQuery = new SolrQuery();

        solrQuery.setQuery(keyWords.toString());

        SearchUtils.setPageQuery(solrQuery,pageQuery);

        SearchUtils.setFilterQuery(solrQuery, filterQuerys);

        SearchUtils.setFacetQuery(solrQuery,facetQuerys);

        setQueryDefault(solrQuery, keyWords);

        SearchResponse<R> searchResponse = new SearchResponse<>();
        QueryResponse response = executeLoopQuery(solrQuery);
        if (null == response) {return searchResponse;}
        searchResponse.setTotal(response.getResults().getNumFound());
        searchResponse.setResponse(getSearchBeans(response));
        searchResponse.setPage(pageQuery.getPage());
        searchResponse.setSize(pageQuery.getSize());
        fetchFacetFields(searchResponse,response);

        LogUtils.info(log,"搜索耗时:{}ms",System.currentTimeMillis()-start);
        return searchResponse;
    }

    /*
     ****************************************私有方法区*******************************************
                   _               _                           _    _                 _
                  (_)             | |                         | |  | |               | |
      _ __   _ __  _ __   __ __ _ | |_  ___   _ __ ___    ___ | |_ | |__    ___    __| |
     | '_ \ | '__|| |\ \ / // _` || __|/ _ \ | '_ ` _ \  / _ \| __|| '_ \  / _ \  / _` |
     | |_) || |   | | \ V /| (_| || |_|  __/ | | | | | ||  __/| |_ | | | || (_) || (_| |
     | .__/ |_|   |_|  \_/  \__,_| \__|\___| |_| |_| |_| \___| \__||_| |_| \___/  \__,_|
     | |
     |_|
     ****************************************私有方法区*******************************************
     */

    /**获取facet结果**/
    private void fetchFacetFields(SearchResponse<R> searchResponse, QueryResponse response){
        List<FacetField> list = response.getFacetFields();
        if(CollectionUtils.isEmpty(list)){
            return;
        }
        FacetFields fields = FacetFields.build();
        for ( FacetField facet : list ) {
            List<FacetField.Count> counts = facet.getValues();
            for ( FacetField.Count count : counts ) {
                fields.add(facet.getName(),count.getName(),count.getCount());
            }
        }
        searchResponse.setFacetFields(fields.fetchAll());
    }

    /**
     * 设置默认查询参数
     **/
    private void setQueryDefault(SolrQuery solrQuery, KeyWords keyWords) {
        solrQuery.set("qf", keyWords.getKey());//可以在这动态设置字段权重
        solrQuery.set("defType", DefType.EDISMAX.name().toLowerCase());
        solrQuery.set("wt", ResultType.JSON.name().toLowerCase());
        solrQuery.set("mm", "90%");
    }

    /**
     * 执行循环搜索
     **/
    private QueryResponse executeLoopQuery(SolrQuery solrQuery) {
        LogUtils.info(log,"执行第1次搜索，搜索参数： {}", solrQuery.toQueryString());
        LogUtils.info(log,"执行第1次搜索，匹配度： {}", "90%");
        QueryResponse response = SearchUtils.executeQuery(getSolrClient(),solrQuery);

        if (response == null) {
            return null;
        }

        //循环搜索
        response = loopQuery(solrQuery, response);
        return response;
    }

    /**
     * 循环搜索
     **/
    private QueryResponse loopQuery(SolrQuery query, QueryResponse response) {
        for (int i = 0, length = mmValues.length; i < length; i++) {
            long numFound = response.getResults().getNumFound();
            if (numFound > 0) {
                break;
            }
            query.set("mm", mmValues[i]);
            LogUtils.info(log, "执行第" + (i + 2) + "次搜索，匹配度： {}", mmValues[i]);
            response = SearchUtils.executeQuery(getSolrClient(),query);
        }
        return response;
    }


}
